package com.lastproject.ejb.dao;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.lastproject.dto.DepartmentDTO;
import com.lastproject.dto.ReportDTO;
import com.lastproject.dto.ReportResultDTO;
import com.lastproject.dto.UserDTO;
import com.lastproject.ejb.entities.Department;
import com.lastproject.ejb.entities.Report;
import com.lastproject.ejb.util.DepartmentConversion;
import com.lastproject.ejb.util.ManipulateFieldsReflection;
import com.lastproject.ejb.util.ReportConversion;

/**
 * Session Bean implementation class ReportDAO
 * 
 * Hodgyai Zoltan
 */
@Stateless
public class ReportDAO implements ReportDAORemote {

	@PersistenceContext(unitName = "LastProjectEJB")
	EntityManager em;

	@EJB
	ReportConversion conv;

	/**
	 * Default constructor.
	 */
	public ReportDAO() {
		super();
	}

	@Override
	public void create(ReportDTO reportDTO) {
		em.persist(conv.fromDTO(reportDTO));
	}

	@Override
	public void edit(ReportDTO reportDTO) {
		em.merge(conv.fromDTO(reportDTO));
	}

	@Override
	public void remove(ReportDTO reportDTO) {
		em.remove(em.merge(conv.fromDTO(reportDTO)));
	}

	@Override
	public ReportDTO findById(int id) {
		Report report = new Report();

		report = em.find(Report.class, id);

		return conv.fromEntity(report);
	}

	@Override
	public List<ReportDTO> getAll() {
		List<Report> rList = new ArrayList<Report>();

		rList = em.createNamedQuery("Report.findAll", Report.class)
				.getResultList();

		List<ReportDTO> rDTOList = new ArrayList<ReportDTO>();

		for (Report r : rList) {
			rDTOList.add(conv.fromEntity(r));
		}

		return rDTOList;

	}

	@Override
	public List<ReportDTO> getGeneralReportsForUser(UserDTO userDTO) {
		List<Report> rList = new ArrayList<Report>();

		rList = em
				.createQuery(
						"SELECT r FROM Report r WHERE r.isConfidential = 0 and r.employee.id = :param",
						Report.class).setParameter("param", userDTO.getId())
				.getResultList();

		List<ReportDTO> rDTOList = new ArrayList<ReportDTO>();

		for (Report r : rList) {
			rDTOList.add(conv.fromEntity(r));
		}

		return rDTOList;

	}

	@Override
	public List<ReportDTO> getAllReportsForUser(UserDTO userDTO) {
		List<Report> rList = new ArrayList<Report>();

		rList = em
				.createQuery(
						"SELECT r FROM Report r WHERE r.employee.id = :param",
						Report.class).setParameter("param", userDTO.getId())
				.getResultList();

		List<ReportDTO> rDTOList = new ArrayList<ReportDTO>();

		for (Report r : rList) {
			rDTOList.add(conv.fromEntity(r));
		}

		return rDTOList;
	}

	/**
	 * @author marinaub
	 * @param ReportDTO
	 *            Method used for getting the results for a specific reports It
	 *            finds all the entities according to the reports' criteria All
	 *            the selected properties are mapped to a ReportResultsDTO class
	 *            using reflection
	 * @return List<ReportResultsDTO>
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<ReportResultDTO> getReportResults(ReportDTO reportDTO) {
		List<ReportResultDTO> reportResult = new ArrayList<ReportResultDTO>();
		List<Object> resultObjects = new ArrayList<Object>();
		String selClause = reportDTO.getSelClause();
		String[] selectedAttributes = selClause.split(",");
		String query = "SELECT r FROM ";

		if (reportDTO.getFromClause() != null)
			query = query + reportDTO.getFromClause() + " r";
		if (reportDTO.getWhereClause() != null)
			query = query + " WHERE " + reportDTO.getWhereClause();
		if (reportDTO.getSortClause() != null)
			query = query + " ORDER BY r." + reportDTO.getSortClause();
		System.out.println(query);

		resultObjects = em.createQuery(query).getResultList();

		for (Object o : resultObjects) {
			ReportResultDTO r = new ReportResultDTO();
			for (int i = 0; i < selectedAttributes.length; i++) {
				if (selectedAttributes[i].equals("department")) {
					DepartmentDTO d = new DepartmentConversion()
							.fromEntity((Department) ManipulateFieldsReflection
									.get(o, selectedAttributes[i]));
					ManipulateFieldsReflection.set(r, selectedAttributes[i], d);
				} else {
					ManipulateFieldsReflection.set(r, selectedAttributes[i],
							ManipulateFieldsReflection.get(o,
									selectedAttributes[i]));
				}

			}
			reportResult.add(r);
		}

		System.out.println(reportResult.size());

		return reportResult;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<String> getAllPositions() {
		List<String> posList = new ArrayList<String>();
		List<String> distList = new ArrayList<String>();
		distList = em.createQuery("SELECT DISTINCT(u.position) FROM User u")
				.getResultList();
		for (String s : distList)
			if (s != null)
				posList.add(s);
		return posList;
	}

	@Override
	public ReportDTO findByNameDateEmployee(String name, Date date, int id) {
		Report report = new Report();
		List<Report> reportList = new ArrayList<Report>();
		reportList = em
				.createQuery(
						"SELECT r FROM Report r WHERE r.name = :name AND r.date = :date AND r.employee.id = :id",
						Report.class).setParameter("name", name)
				.setParameter("date", date).setParameter("id", id)
				.getResultList();
		if (reportList.size() != 0) {
			report = reportList.get(0);
			return conv.fromEntity(report);
		} else {
			return null;
		}
	}
}
